import {ValidatorsDef} from './validators.d'
import {helpers} from '@vuelidate/validators'
import {ValidationRuleWithoutParams, ValidationRuleWithParams} from '@vuelidate/core'
import {Ref, unref} from 'vue'
import _ from 'lodash'
import dayjs from 'dayjs'
import i18n from '../i18n/i18n'

const {t} = i18n.global
const alwaysRight = () => true

const required: ValidationRuleWithoutParams = {
  $validator: (value: any) => !!helpers.req(value),
  $message: t('不可为空')
}

const requiredIf: (condition: boolean | Ref<boolean>) => ValidationRuleWithoutParams = function (condition: boolean | Ref<boolean>) {
  return {
    $validator: (value: any) => !unref(condition) || !!helpers.req(value),
    $message: t('不可为空')
  }
}
const productionDate: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidProductionDate(value as string),
  $message: t('必须为yyyyMMdd或yyyyWW格式')
}

const productionDate6: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidProductionDate(value as string, 6),
  $message: t('必须为yyyyWW格式')
}

const productionDate8: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidProductionDate(value as string, 8),
  $message: t('必须为yyyyMMdd格式')
}

const mfAbbrName: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidMfAbbrName(value as string),
  $message: t('应为不含空格的2-50个字符')
}

const realName: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidRealName(value as string),
  $message: t('请填入正确的真实中文名或英文名')
}

const username: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidUserName(value as string),
  $message: t('应由字母、数字、汉字或“._-”组成，2-20个字符')
}

const password: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidPassword(value as string),
  $message: t('密码应由字母、数字、下划线或~!@#$%^&*().,+-=:<>/?;|[]_等特殊符号组成，6-20个字符')
}

const strictPassword: ValidationRuleWithoutParams<string | null> = {
   $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidStrictPassword(value as string),
    $message: t('密码应由大写字母、小写字母、数字及~!@#$%^&*().,+-=:<>/?;|[]_等特殊符号中的至少三种组成，8-20个字符')
}

const passwordConfirm: (password: Ref<string>) => ValidationRuleWithParams<{ password: Ref<string> }, string | null> = function (password: Ref<string>) {
  return {
    $validator: (value: string | null) => !helpers.req(value) || !helpers.req(password) || password.value === value,
    $message: () => t('两次密码输入必须相同'),
    $params: {password}
  }
}

const phone: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidPhone(value as string),
  $message: t('请提供正确的手机号码')
}

const email: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidEmail(value as string),
  $message: t('请提供正确的Email')
}

const int32: ValidationRuleWithoutParams<string | number | null> = {
  $validator: (value: string | number | null) => !helpers.req(value) || $f.valFuncs.isValidInt32(value as string | number),
  $message: t('数值不合法')
}

const decimal: (decimalNum: number) => ValidationRuleWithParams<{ decimalNum: number }, string | number | null> = function (decimalNum: number) {
  return {
    $validator: (value: string | number | null) => !helpers.req(value) || $f.valFuncs.isValidDecimal(value as string | number, decimalNum),
    $message: (input) => t('必须是小数位不超过{decimal}位的数字', {decimal: input.$params.decimalNum}),
    $params: {decimalNum}
  }
}

const decimalAny: ValidationRuleWithoutParams<string | number | null> = {
  $validator: (value: string | number | null) => !helpers.req(value) || $f.valFuncs.isValidDecimalAny(value as string | number),
  $message: t('必须是有效数字')
}

const greaterThan: (target: number | string | null | Ref<number | string | null>)
  => ValidationRuleWithParams<{ target: number | string | null | Ref<number | string | null> }, string | number | null>
  = function (target: number | string | null | Ref<number | string | null>) {
  return {
    $validator: (value: string | number | null) => {
      if (!helpers.req(value) || !helpers.req(target)) {
        return true
      }
      const targetVal = _.toNumber(unref(target))
      const thisVal = _.toNumber(value)
      if (_.isFinite(thisVal) && _.isFinite(targetVal)) {
        return thisVal > targetVal
      }
      return true
    },
    $message: (input) => t('必须大于{decimal}',{decimal: unref(input.$params.target)}),
    $params: {target}
  }
}

const greaterEqualThan: (target: number | string | null | Ref<number | string | null>)
  => ValidationRuleWithParams<{ target: number | string | null | Ref<number | string | null> }, string | number | null>
  = function (target: number | string | null | Ref<number | string | null>) {
  return {
    $validator: (value: string | number | null) => {
      if (!helpers.req(value) || !helpers.req(target)) {
        return true
      }
      const targetVal = _.toNumber(unref(target))
      const thisVal = _.toNumber(value)
      if (_.isFinite(thisVal) && _.isFinite(targetVal)) {
        return thisVal >= targetVal
      }
      return true
    },
    $message: (input) => t('必须大于等于{decimal}',{decimal: unref(input.$params.target)}),
    $params: {target}
  }
}
const lessThan: (target: number | string | null | Ref<number | string | null>)
  => ValidationRuleWithParams<{ target: number | string | null | Ref<number | string | null> }, string | number | null>
  = function (target: number | string | null | Ref<number | string | null>) {
  return {
    $validator: (value: string | number | null) => {
      if (!helpers.req(value) || !helpers.req(target)) {
        return true
      }
      const targetVal = _.toNumber(unref(target))
      const thisVal = _.toNumber(value)
      if (_.isFinite(thisVal) && _.isFinite(targetVal)) {
        return thisVal < targetVal
      }
      return true
    },
    $message: (input) => t('必须小于{decimal}',{decimal: unref(input.$params.target)}),
    $params: {target}
  }
}

const lessEqualThan: (target: number | string | null | Ref<number | string | null>)
  => ValidationRuleWithParams<{ target: number | string | null | Ref<number | string | null> }, string | number | null>
  = function (target: number | string | null | Ref<number | string | null>) {
  return {
    $validator: (value: string | number | null) => {
      if (!helpers.req(value) || !helpers.req(target)) {
        return true
      }
      const targetVal = _.toNumber(unref(target))
      const thisVal = _.toNumber(value)
      if (_.isFinite(thisVal) && _.isFinite(targetVal)) {
        return thisVal <= targetVal
      }
      return true
    },
    $message: (input) => t('必须小于等于{decimal}',{decimal: unref(input.$params.target)}),
    $params: {target}
  }
}

// 数值比较：介于...之间(开区间)
const betweenOpen: (min: number | string | null | Ref<number | string | null>, max: number | string | null | Ref<number | string | null>)
  => ValidationRuleWithParams<{ min: number | string | null | Ref<number | string | null>, max: number | string | null | Ref<number | string | null> }, string | number | null>
  = function (min: number | string | null | Ref<number | string | null>, max: number | string | null | Ref<number | string | null>) {
  return {
    $validator: (value: string | number | null) => {
      if (!helpers.req(value) || !helpers.req(min) || !helpers.req(max)) {
        return true
      }
      const minVal = _.toNumber(unref(min))
      const maxVal = _.toNumber(unref(max))
      const thisVal = _.toNumber(value)
      if (_.isFinite(thisVal) && _.isFinite(minVal) && _.isFinite(maxVal)) {
        return thisVal > minVal && thisVal < maxVal
      }
      return true
    },
    $message: (input) => t('必须大于{min}并小于{max}',{min: unref(input.$params.min), max: unref(input.$params.max)}),
    $params: {min, max}
  }
}

// 数值比较：介于...之间(闭区间)
const betweenClosed: (min: number | string | null | Ref<number | string | null>, max: number | string | null | Ref<number | string | null>)
  => ValidationRuleWithParams<{ min: number | string | null | Ref<number | string | null>, max: number | string | null | Ref<number | string | null> }, string | number | null>
  = function (min: number | string | null | Ref<number | string | null>, max: number | string | null | Ref<number | string | null>) {
  return {
    $validator: (value: string | number | null) => {
      if (!helpers.req(value) || !helpers.req(min) || !helpers.req(max)) {
        return true
      }
      const minVal = _.toNumber(unref(min))
      const maxVal = _.toNumber(unref(max))
      const thisVal = _.toNumber(value)
      if (_.isFinite(thisVal) && _.isFinite(minVal) && _.isFinite(maxVal)) {
        return thisVal >= minVal && thisVal <= maxVal
      }
      return true
    },
    $message: (input) => t('必须大于等于{min}并小于等于{max}',{min: unref(input.$params.min), max: unref(input.$params.max)}),
    $params: {min, max}
  }
}

const isMultiply: (target: number | string | null | Ref<number | string | null>)
  => ValidationRuleWithParams<{ target: number | string | null | Ref<number | string | null> }, string | number | null>
  = function (target: number | string | null | Ref<number | string | null>) {
  return {
    $validator: (value: string | number | null) => {
      if (!helpers.req(value) || !helpers.req(target)) {
        return true
      }
      const targetVal = _.toNumber(unref(target))
      const thisVal = _.toNumber(value)
      if (_.isFinite(thisVal) && _.isFinite(targetVal)) {
        return targetVal > 0 && thisVal > 0 && thisVal % targetVal === 0
      }
      return true
    },
    $message: (input) => t('必须是{decimal}的整数倍', {decimal: unref(input.$params.target)}),
    $params: {target}
  }
}

const isDivisible: (target: number | string | null | Ref<number | string | null>)
  => ValidationRuleWithParams<{ target: number | string | null | Ref<number | string | null> }, string | number | null>
  = function (target: number | string | null | Ref<number | string | null>) {
  return {
    $validator: (value: string | number | null) => {
      if (!helpers.req(value) || !helpers.req(target)) {
        return true
      }
      const targetVal = _.toNumber(unref(target))
      const thisVal = _.toNumber(value)
      if (_.isFinite(thisVal) && _.isFinite(targetVal)) {
        return targetVal % thisVal === 0
      }
      return true
    },
    $message: (input) => t('必须能被{decimal}整除', {decimal: unref(input.$params.target)}),
    $params: {target}
  }
}

const date: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidDate(value as string, false),
  $message: t('请输入正确日期(格式yyyy-MM-dd)')
}

const multiFmtDate: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidDate(value as string, true),
  $message: t('请输入正确日期')
}

const time: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidTime(value as string),
  $message: t('请输入正确时间')
}

const datetime: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidDatetime(value as string),
  $message: t('请输入正确日期时间(格式yyyy-MM-dd HH:mm)')
}

const datetimeWithSec: ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.isValidDate(value as string, true),
  $message: t('请输入正确日期时间(格式yyyy-MM-dd HH:mm:ss)')
}

const equal: (target: string | null | Ref<string | null>)
  => ValidationRuleWithParams<{ target: string | null | Ref<string | null> }> = function (target: string | null | Ref<string | null>) {
  return {
    $validator: (value: string) => !helpers.req(value) || !helpers.req(target) || value === unref(target),
    $message: (input) => t('必须等于{decimal}',{decimal: unref(input.$params.target)}),
    $params: {target}
  }
}

const notEqual: (target: string | null | Ref<string | null>)
  => ValidationRuleWithParams<{ target: string | null | Ref<string | null> }> = function (target: string | null | Ref<string | null>) {
  return {
    $validator: (value: string) => !helpers.req(value) || !helpers.req(target) || value !== unref(target),
    $message: (input) => t('必须不等于{decimal}',{decimal: unref(input.$params.target)}),
    $params: {target}
  }
}

const dateGreaterThan: (target: string | null | Ref<string | null>)
  => ValidationRuleWithParams<{ target: string | null | Ref<string | null> }, string | null>
  = function (target: string | null | Ref<string | null>) {
  return {
    $validator: (value: string | null) => {
      if (!helpers.req(value) || !helpers.req(target)) {
        return true
      }
      const thisVal = dayjs(value)
      const tgtVal = dayjs(unref(target))
      if (thisVal.isValid() && tgtVal.isValid()) {
        return thisVal > tgtVal
      }
      return true
    },
    $message: (input) => t('必须大于{decimal}', {decimal: unref(input.$params.target)}),
    $params: {target}
  }
}

const dateGreaterEqualThan: (target: string | null | Ref<string | null>)
  => ValidationRuleWithParams<{ target: string | null | Ref<string | null> }, string | null>
  = function (target: string | null | Ref<string | null>) {
  return {
    $validator: (value: string | null) => {
      if (!helpers.req(value) || !helpers.req(target)) {
        return true
      }
      const thisVal = dayjs(value)
      const tgtVal = dayjs(unref(target))
      if (thisVal.isValid() && tgtVal.isValid()) {
        return thisVal >= tgtVal
      }
      return true
    },
    $message: (input) => t('必须大于等于{decimal}', {decimal: unref(input.$params.target)}),
    $params: {target}
  }
}

const dateLessThan: (target: string | null | Ref<string | null>)
  => ValidationRuleWithParams<{ target: string | null | Ref<string | null> }, string | null>
  = function (target: string | null | Ref<string | null>) {
  return {
    $validator: (value: string | null) => {
      if (!helpers.req(value) || !helpers.req(target)) {
        return true
      }
      const thisVal = dayjs(value)
      const tgtVal = dayjs(unref(target))
      if (thisVal.isValid() && tgtVal.isValid()) {
        return thisVal < tgtVal
      }
      return true
    },
    $message: (input) => t('必须小于{decimal}', {decimal: unref(input.$params.target)}),
    $params: {target}
  }
}

const dateLessEqualThan: (target: string | null | Ref<string | null>)
  => ValidationRuleWithParams<{ target: string | null | Ref<string | null> }, string | null>
  = function (target: string | null | Ref<string | null>) {
  return {
    $validator: (value: string | null) => {
      if (!helpers.req(value) || !helpers.req(target)) {
        return true
      }
      const thisVal = dayjs(value)
      const tgtVal = dayjs(unref(target))
      if (thisVal.isValid() && tgtVal.isValid()) {
        return thisVal <= tgtVal
      }
      return true
    },
    $message: (input) => t('必须小于等于{decimal}', {decimal: unref(input.$params.target)}),
    $params: {target}
  }
}

const dateBetweenOpen: (begin: string | null | Ref<string | null>, end: string | null | Ref<string | null>)
  => ValidationRuleWithParams<{ begin: string | null | Ref<string | null>, end: string | null | Ref<string | null> }, string | null>
  = function (begin: string | null | Ref<string | null>, end: string | null | Ref<string | null>) {
  return {
    $validator: (value: string | null) => {
      if (!helpers.req(value) || !helpers.req(begin) || !helpers.req(end)) {
        return true
      }
      const thisVal = dayjs(value)
      const beginVal = dayjs(unref(begin))
      const endVal = dayjs(unref(end))
      if (thisVal.isValid() && beginVal.isValid() && endVal.isValid()) {
        return thisVal > beginVal && thisVal < endVal
      }
      return true
    },
    $message: (input) => t('必须大于{min}并小于{max}', {min: unref(input.$params.begin),max: unref(input.$params.end)}),
    $params: {begin, end}
  }
}

const dateBetweenClose: (begin: string | null | Ref<string | null>, end: string | null | Ref<string | null>)
  => ValidationRuleWithParams<{ begin: string | null | Ref<string | null>, end: string | null | Ref<string | null> }, string | null>
  = function (begin: string | null | Ref<string | null>, end: string | null | Ref<string | null>) {
  return {
    $validator: (value: string | null) => {
      if (!helpers.req(value) || !helpers.req(begin) || !helpers.req(end)) {
        return true
      }
      const thisVal = dayjs(value)
      const beginVal = dayjs(unref(begin))
      const endVal = dayjs(unref(end))
      if (thisVal.isValid() && beginVal.isValid() && endVal.isValid()) {
        return thisVal >= beginVal && thisVal <= endVal
      }
      return true
    },
    $message: (input) => t('必须大于等于{min}并小于等于{max}', {min: unref(input.$params.begin),max: unref(input.$params.end)}),
    $params: {begin, end}
  }
}

const minLength: (len: number | null | Ref<number | null>)
  => ValidationRuleWithParams<{ len: number | null | Ref<number | null> }, string | null>
  = function (len: number | null | Ref<number | null>) {
  return {
    $validator: (value: string | null) => !helpers.req(value) || !helpers.req(len) || value!.length >= (unref(len) as number),
    $message: (input) => t('长度不得小于{len}',{len: unref(input.$params.len)}),
    $params: {len}
  }
}

const maxLength: (len: number | null | Ref<number | null>)
  => ValidationRuleWithParams<{ len: number | null | Ref<number | null> }, string | null>
  = function (len: number | null | Ref<number | null>) {
  return {
    $validator: (value: string | null) => !helpers.req(value) || !helpers.req(len) || value!.length <= (unref(len) as number),
    $message: (input) => t('长度不得超过{len}',{len: unref(input.$params.len)}),
    $params: {len}
  }
}

const equalLength: (len: number | null | Ref<number | null>)
  => ValidationRuleWithParams<{ len: number | null | Ref<number | null> }, string | null>
  = function (len: number | null | Ref<number | null>) {
  return {
    $validator: (value: string | null) => !helpers.req(value) || !helpers.req(len) || value!.length === (unref(len) as number),
    $message: (input) => t('长度必须为{len}',{len: unref(input.$params.len)}),
    $params: {len}
  }
}

const regex: (regExp: RegExp | Ref<RegExp>, errMsg?: string | Ref<string>)
  => ValidationRuleWithoutParams<string | null>
  = function (regExp: RegExp | Ref<RegExp>, errMsg: string | Ref<string> | undefined) {
  return {
    $validator: (value: string | null) => !helpers.req(value) || unref(regExp).test(value as string),
    $message: () => errMsg ? unref(errMsg) : t('格式不正确')
  }
}

const extraPasswordRepeatCheck:ValidationRuleWithoutParams<string | null> = {
  $validator: (value: string | null) => !helpers.req(value) || $f.valFuncs.extraPasswordRepeatCheck (value as string)==='',
  $message: ()=> t('密码中存在超过3个连续的重复字符、字符序字符或键盘序字符')
}

export default {
  alwaysRight,
  required,
  requiredIf,
  productionDate,
  productionDate6,
  productionDate8,
  mfAbbrName,
  realName,
  username,
  password,
  strictPassword,
  passwordConfirm,
  phone,
  email,
  int32,
  decimal,
  decimalAny,
  greaterThan,
  greaterEqualThan,
  lessThan,
  lessEqualThan,
  betweenOpen,
  betweenClosed,
  isMultiply,
  isDivisible,
  date,
  multiFmtDate,
  time,
  datetime,
  datetimeWithSec,
  equal,
  notEqual,
  dateGreaterThan,
  dateGreaterEqualThan,
  dateLessThan,
  dateLessEqualThan,
  dateBetweenOpen,
  dateBetweenClose,
  minLength,
  maxLength,
  equalLength,
  regex,
  extraPasswordRepeatCheck
} as ValidatorsDef
